package com.ruoyi.config.pdf.utils;

import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfDocumentContentParser;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import com.ruoyi.config.pdf.common.FinalTemp;
import com.ruoyi.config.pdf.common.Template;
import com.ruoyi.config.pdf.common.TemplateEnum;
import com.ruoyi.config.pdf.vo.PdfReqVo;

import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.List;

/**
 * @author yjc
 * @create 2023-04-11 11:29
 */
@Slf4j
public class PdfUtils {


    /**
     * @param reqVo
     * @param template
     * @return
     * @throws Exception
     */
    public static Table getTable(PdfReqVo reqVo, Template template) throws Exception {

        //在创建字体时直接使用即可解决中文问题
        PdfFont sysFont = PdfFontFactory.createFont("static/simhei.otf", PdfEncodings.IDENTITY_H, true);

        //获取列数以及单元格宽度(以50F为一个标准单位)
        List<Integer> cellList = template.getCellList();
        //生成标准单元格
        long len = cellList.stream().mapToInt(Integer::intValue).summaryStatistics().getSum();
        float[] pointColumnWidths = new float[(int) len];
        for (int i = 0; i < pointColumnWidths.length; i++) {
            pointColumnWidths[i] = 50f;//标准长度
        }

        //生成表格
        Table table = new Table(pointColumnWidths);
        int cellLen = pointColumnWidths.length;

        //填充标题
        addTitle(sysFont, cellLen, table, reqVo, template);
        //填充两行基本数据（按照一行数据个数动态计算分隔数）
        addTwoBasicData(sysFont, cellLen, table, reqVo, template);

        //填充表格信息
        addTableData(reqVo, sysFont, cellList, table, template);

        //填充最终内容
        addFinalData(sysFont, cellList, cellLen, table, reqVo, template);

        return table;
    }

    /**
     * 填充最终内容
     *
     * @param sysFont
     * @param cellList
     * @param cellLen
     * @param table
     */
    private static void addFinalData(PdfFont sysFont, List<Integer> cellList, int cellLen, Table table, PdfReqVo reqVo, Template template) {
        //第一块
        addFinalOnePart(sysFont, cellList, table, template);
        //第二块
        //上半部分（后面统一使用switch）
        TemplateEnum templateEnum = TemplateEnum.getTemplateEnum(reqVo.getTemplate());
        switch (templateEnum) {
            case TEMPLATE1:
            case TEMPLATE4:
                FinalTemp.addFinalTwoPart1And4(sysFont, cellList, cellLen, table, reqVo);
                break;
            case TEMPLATE2:
                FinalTemp.addFinalTwoPart2(sysFont, cellList, cellLen, table, reqVo);
                break;
            case TEMPLATE3:
                FinalTemp.addFinalTwoPart3(sysFont, cellList, cellLen, table, reqVo);
                break;
            case TEMPLATE5:
                FinalTemp.addFinalTwoPart5(sysFont, cellList, cellLen, table, reqVo);
                break;
            case TEMPLATE6:
                FinalTemp.addFinalTwoPart6(sysFont, cellList, cellLen, table, reqVo);
                break;
            case TEMPLATE7:
            case TEMPLATE8:
                FinalTemp.addFinalTwoPart7And8(sysFont, cellList, cellLen, table, reqVo);
                break;
        }
        //下半部分(审批部分)
        addFinalApproval(sysFont, cellList, cellLen, table, reqVo, template);
    }

    /**
     * 填充表格信息
     *
     * @param reqVo
     * @param sysFont
     * @param cellList
     * @param table
     */
    private static void addTableData(PdfReqVo reqVo, PdfFont sysFont, List<Integer> cellList, Table table, Template template) {
        Cell cell;//填充表头信息
        List<String> headTableList = template.getHeadTableList();
        for (int j = 0; j < cellList.size(); j++) {
            cell = new Cell(1, cellList.get(j));
//            cell.setBackgroundColor(new DeviceRgb(255, 255, 255));
            cell.setTextAlignment(TextAlignment.CENTER);
            cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
            table.addCell(cell.add(new Paragraph(headTableList.get(j))
                    .setFont(sysFont)
                    .setFontSize(8f)
                    .setTextAlignment(TextAlignment.CENTER)
                    .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    .setBold()));
        }

        //填充主体内容信息
        List<List<String>> content = reqVo.getContent();
        Integer rows = content.size();
        for (int i = 0; i < rows; i++) {
            cell = new Cell(1, cellList.get(0));
            table.addCell(cell.add(new Paragraph(i + 1 + "")
                    .setFontSize(8f)
                    .setFont(sysFont))
                    .setTextAlignment(TextAlignment.CENTER)
                    .setVerticalAlignment(VerticalAlignment.MIDDLE));
            List<String> subContent = content.get(i);
            if (subContent.size() != (headTableList.size() - 1)) {
                throw new RuntimeException("表格主体数据数量有误，第" + (i + 1) + "行");
            }
            for (int j = 1; j < cellList.size(); j++) {
                cell = new Cell(1, cellList.get(j));
//                cell.setBackgroundColor(new DeviceRgb(255, 255, 255));
                cell.setTextAlignment(TextAlignment.CENTER);
                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
                table.addCell(cell.add(new Paragraph(subContent.get(j - 1))
                        .setFont(sysFont)
                        .setFontSize(8f)
                        .setTextAlignment(TextAlignment.CENTER)
                        .setVerticalAlignment(VerticalAlignment.MIDDLE)));
            }
        }
    }

    /**
     * 填充两行基本数据（按照一行数据个数动态计算分隔数）
     *
     * @param sysFont
     * @param cellLen
     * @param table
     * @param reqVo
     * @param template
     */
    private static void addTwoBasicData(PdfFont sysFont, int cellLen,
                                        Table table, PdfReqVo reqVo, Template template) {
        //第一行
        List<String> oneBasicList = reqVo.getOneBasicList();
        List<String> oneTempList = template.getOneTempList();
        if (oneBasicList.size() != oneTempList.size()) {
            throw new RuntimeException("表格第一行数据数量有误，");
        }
        int oneLen = oneBasicList.size();
        Cell cell;
        for (int i = 0; i < oneLen; i++) {
            cell = (i == oneLen - 1) ? new Cell(1, cellLen / oneLen + cellLen % oneLen)
                    : new Cell(1, cellLen / oneLen);
            table.addCell(cell
                    .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    .add(new Paragraph(oneTempList.get(i))
                            .add(oneBasicList.get(i))
                            .setFont(sysFont)
                            .setFontSize(8f))
                    .setBorder(Border.NO_BORDER));
        }


        //第二行
        List<String> twoBasicList = reqVo.getTwoBasicList();
        List<String> twoTempList = template.getTwoTempList();
        if (oneBasicList.size() != oneTempList.size()) {
            throw new RuntimeException("表格第二行数据数量有误，");
        }
        int twoLen = twoBasicList.size();
        for (int i = 0; i < twoLen; i++) {
            cell = (i == twoLen - 1) ? new Cell(1, cellLen / twoLen + cellLen % twoLen)
                    : new Cell(1, cellLen / twoLen);
            table.addCell(cell
                    .setHeight(20f)
                    .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    .add(new Paragraph(twoTempList.get(i))
                            .add(twoBasicList.get(i))
                            .setFont(sysFont)
                            .setFontSize(8f))
                    .setBorder(Border.NO_BORDER));
        }
    }

    /**
     * 填充标题
     *
     * @param sysFont
     * @param cellLen
     * @param table
     */
    private static void addTitle(PdfFont sysFont, int cellLen, Table table, PdfReqVo reqVo, Template template) {
        Cell cell;
        cell = new Cell(1, cellLen);
        table.addCell(cell.add(new Paragraph(template.getTitle())
                .setFont(sysFont)
                .setBold()
                .setTextAlignment(TextAlignment.CENTER)
                .setFontSize(10f))
                .setBorder(Border.NO_BORDER));
    }


    /**
     * 填充下半部分(审批部分)
     *
     * @param sysFont
     * @param cellList
     * @param cellLen
     * @param table
     * @param reqVo
     * @param template
     */
    private static void addFinalApproval(PdfFont sysFont, List<Integer> cellList, int cellLen, Table table, PdfReqVo reqVo, Template template) {
        Cell cell;
        List<String> approvalList = reqVo.getApprovalList();
        List<String> fourTempList = template.getFourTempList();
        if (approvalList.size() != fourTempList.size()) {
            throw new RuntimeException("表格最终部分下半部分数据数量有误");
        }
        for (int i = 0; i < fourTempList.size(); i++) {
            cell = i == fourTempList.size() - 1 ? new Cell(1, (cellLen - (cellList.get(0) + cellList.get(1))) / 3 + (cellLen - (cellList.get(0) + cellList.get(1))) % 3) :
                    new Cell(1, (cellLen - (cellList.get(0) + cellList.get(1))) / 3);
            if (i == 0) {
                cell.setBorderRight(Border.NO_BORDER);
            } else if (i == fourTempList.size() - 1) {
                cell.setBorderLeft(Border.NO_BORDER);
            } else {
                cell.setBorderRight(Border.NO_BORDER);
                cell.setBorderLeft(Border.NO_BORDER);
            }
            table.addCell(cell
                    .setHeight(50f)
                    .setBorderTop(Border.NO_BORDER)
                    .add(new Paragraph(fourTempList.get(i))
                            .add(approvalList.get(i)))
                    .setFontSize(8f)
                    .setFont(sysFont)
                    .setTextAlignment(TextAlignment.LEFT)
                    .setVerticalAlignment(VerticalAlignment.MIDDLE));
        }
    }

    /**
     * 填充最终部分第一块内容
     *
     * @param sysFont
     * @param cellList
     * @param table
     * @param template
     */
    private static void addFinalOnePart(PdfFont sysFont, List<Integer> cellList, Table table, Template template) {
        String finalDataType = template.getThreeTemp();
        Cell cell;
        cell = new Cell(2, cellList.get(0) + cellList.get(1));
        table.addCell(cell
                .add(new Paragraph(finalDataType))
                .setFontSize(8f)
                .setFont(sysFont)
                .setTextAlignment(TextAlignment.CENTER)
                .setVerticalAlignment(VerticalAlignment.MIDDLE));
    }

    /**
     * @param input
     * @param sealImgMap
     * @param signImgMap
     * @param pageNum
     */
    // TODO 上传服务器地址
    public static String setSignAndSealRect(String input, Map<String, Image> sealImgMap,
                                          Map<String, Image> signImgMap, int pageNum, Template template) {
        //图片版pdf保存地址
        String dest = "D:\\ruoyi\\uploadPath\\uploadPdf\\"+ template.getTitle() + DateUtils.nowFormatTimeToUrl()  + "_pic" + ".pdf";
//         String dest = "C:\\wusihao\\pdfCreate\\" + template.getTitle() + DateUtils.nowFormatTimeToUrl() + "_pic.pdf";

        float width = 100f;//图片大小

        //盖章图片位置map
        Map<String, Rectangle> sealRectMap = new HashMap<>();
        //签名图片位置map
        Map<String, Rectangle> signRectMap = new HashMap<>();

        try {
            //核心思路为对PdfDocument对象采用某种Strategy，这里使用RegexBasedLocationExtractionStrategy
            PdfReader pr = new PdfReader(input);//pdf文件地址
            PdfDocument pd = new PdfDocument(pr);
            PdfDocumentContentParser pdcp = new PdfDocumentContentParser(pd);


            getRectMap(sealImgMap.keySet(), pageNum, pdcp, sealRectMap);
            getRectMap(signImgMap.keySet(), pageNum, pdcp, signRectMap);
            pr.close();
            pd.close();

            // 2、创建PdfDocument实例对象
            PdfDocument pdf = new PdfDocument(new PdfReader(input), new PdfWriter(dest));
            PdfCanvas pdfCanvas = new PdfCanvas(pdf, 1);

//            Rectangle rectangle = new Rectangle(38.25f, 774.52997f, image.getImageWidth(), image.getImageHeight());
            for (Map.Entry<String, Image> key : sealImgMap.entrySet()) {
                Image image = key.getValue();
                Rectangle rectangle = sealRectMap.get(key.getKey());
                rectangle.setY(rectangle.getTop() + 25);//将盖章往上移动
                rectangle.setWidth(width);//固定盖章大小
                Canvas canvas = new Canvas(pdfCanvas, pdf, rectangle);
                canvas.add(image);
                canvas.close();
            }
            for (Map.Entry<String, Image> key : signImgMap.entrySet()) {
                Image image = key.getValue();
                Rectangle rectangle = signRectMap.get(key.getKey());
                rectangle.setX(rectangle.getRight() + 15);//将盖章往右移
                rectangle.setY(rectangle.getTop());//将盖章往上移动
                rectangle.setWidth(width);//固定盖章大小
                Canvas canvas = new Canvas(pdfCanvas, pdf, rectangle);
                canvas.add(key.getValue());
                canvas.close();
            }
            pdf.close();

        } catch (Exception e) {
            System.err.println("read file failed!");
            e.printStackTrace();
        }

        return dest;
    }

    private static void getRectMap(Set<String> keySet, int pageNum, PdfDocumentContentParser pdcp, Map<String, Rectangle> rectMap) {
        for (String key : keySet) {
            RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(key);

            //文本内容具体解析借助使用PdfDocumentContentParser类(实质使用PdfCanvasProcessor进行处理)， 对待处理页面装配合适策略
            RegexBasedLocationExtractionStrategy regexStrategy =
                    pdcp.processContent(pageNum, strategy);
            //获取处理结果
            Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
            //自定义结果处理
            if (!resultantLocations.isEmpty()) {
                for (IPdfTextLocation item : resultantLocations) {
                    Rectangle boundRectangle = item.getRectangle();
                    System.out.println(item.getText());
                    log.info("关键字：{}", item.getText());
                    log.info("{} location of x{}:    ,y{} ", item.getText(), boundRectangle.getX(), boundRectangle.getY());
                    log.info("{} location of width{}:   ,height: {}", item.getText(), boundRectangle.getWidth(), boundRectangle.getHeight());
                    rectMap.put(key, boundRectangle);

                }
            } else {
                System.out.println("the result is null");
            }
        }
    }


}
